﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.ServiceModel;
using System.ServiceModel.Security;
using NLog;
using DeSleeper.Library;

namespace DeSleeper.Service
{
    public class WakeUpService : IWakeUpService
    {
		private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        public void WakeUp(string macAddress)
        {
        	checkSecurity();
        	WakeOnLanHelper.WakeUp(macAddress);
        }

    	public void WakeUpByHostName(string hostName)
		{
			checkSecurity();
			TargetCache.Instance.WakeUpRegisteredHost(hostName);
		}

    	/// <exception cref="SecurityAccessDeniedException">Anonymous access is not supported.</exception>
		/// <exception cref="InvalidOperationException">
		/// Service has not been configured properly or User is not a member of the domain user group.
		/// </exception>
    	private static void checkSecurity()
    	{
    		var identity = OperationContext.Current.ServiceSecurityContext.WindowsIdentity;
    		if (!identity.IsAuthenticated || identity.IsAnonymous || identity.IsGuest)
    			throw new SecurityAccessDeniedException("Anonymous access is not supported.");

    		var principal = new WindowsPrincipal(identity);
    		var serviceUserIdentity = WindowsIdentity.GetCurrent();
    		_logger.Info("Current User {0}", serviceUserIdentity);
    		if (serviceUserIdentity == null)
    			throw new InvalidOperationException("Service has not been configured properly.");

    		_logger.Info("Current User SID {0}", serviceUserIdentity.User);
    		var accountDomainSid = serviceUserIdentity.User.AccountDomainSid;
    		_logger.Info("Current Domain SID {0}", accountDomainSid);

    		// Local user group if not on a domain
    		var userSid = accountDomainSid == null
    		              	? new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null)
    		              	: new SecurityIdentifier(WellKnownSidType.AccountDomainUsersSid, accountDomainSid);

    		if (!principal.IsInRole(userSid))
    			throw new SecurityAccessDeniedException("User is not a member of the domain user group.");
    	}
    }
}